package com.bestcem.xm.user.service.impl;

import cn.hutool.core.lang.ObjectId;
import com.alibaba.fastjson.JSON;
import com.bestcem.xm.common.core.constant.AppResourceErrorCode;
import com.bestcem.xm.common.core.constant.ResourceErrorCodeConstants;
import com.bestcem.xm.common.core.domain.web.ServiceResult;
import com.bestcem.xm.common.core.enums.AuthErrorCodeEnum;
import com.bestcem.xm.common.core.enums.ReqErrorCodeEnum;
import com.bestcem.xm.common.core.enums.ResourceErrorCodeEnum;
import com.bestcem.xm.common.core.enums.ValidationErrorCodeEnum;
import com.bestcem.xm.common.core.uitls.DateUtil;
import com.bestcem.xm.componet.filestorage.service.StorageService;
import com.bestcem.xm.componet.redis.service.RedisService;
import com.bestcem.xm.user.config.properties.SampleProperties;
import com.bestcem.xm.user.config.properties.SettingProperties;
import com.bestcem.xm.user.config.properties.info.SampleOrgInfo;
import com.bestcem.xm.user.constant.CommonConstant;
import com.bestcem.xm.user.constant.SmsConstant;
import com.bestcem.xm.user.constant.UserCacheKeyConstant;
import com.bestcem.xm.user.constant.UserOutterCacheKeyConstant;
import com.bestcem.xm.user.controller.vo.user.TicketSubscribeWxVO;
import com.bestcem.xm.user.dao.UserAccountDao;
import com.bestcem.xm.user.entity.mysql.User;
import com.bestcem.xm.user.entity.pojo.UserDO;
import com.bestcem.xm.user.enums.*;
import com.bestcem.xm.user.grpc.client.IndustryGrpcService;
import com.bestcem.xm.user.grpc.client.PackageGrpcService;
import com.bestcem.xm.user.grpc.client.UserWechatGrpcService;
import com.bestcem.xm.user.grpc.client.UserWechatWorkGrpcService;
import com.bestcem.xm.user.grpc.client.dto.*;
import com.bestcem.xm.user.service.*;
import com.bestcem.xm.user.service.dto.order.RecordToOmDTO;
import com.bestcem.xm.user.service.dto.redis.FastCreateUserDTO;
import com.bestcem.xm.user.service.dto.redis.UserLoginSessionDTO;
import com.bestcem.xm.user.service.dto.redis.UserRegisterDTO;
import com.bestcem.xm.user.service.dto.user.*;
import com.bestcem.xm.user.service.third.BaiduOcpcService;
import com.bestcem.xm.user.service.third.GrowingIOService;
import com.bestcem.xm.user.service.third.PhoneService;
import com.bestcem.xm.user.util.business.*;
import com.bestcem.xm.user.util.convert.UserConvert;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.util.*;


/**
 * 微信相关服务
 *
 * @author qiongyu.cui <qiongyu.cui@idiaoyan.com>
 * @version v1.0
 * @date 2022/3/30 18:37
 */
@Slf4j
@Service
public class UserWxServiceImpl implements UserWxService {

    private static final Random rand = new Random();

    @Resource
    private SettingProperties settingProperties;

    @Autowired
    private UserService userService;

    @Resource
    private OrganizationService organizationService;

    @Resource
    private UserAuthService userAuthService;

    @Autowired
    private PackageGrpcService packageGrpcService;

    @Autowired
    private IndustryGrpcService industryGrpcService;

    @Autowired
    private SequenceService sequenceService;

    @Resource
    private UserBookingTrackService trackService;

    @Autowired
    private GrowingIOService growingIoService;

    @Resource
    private SampleProperties sampleProperties;

    @Resource
    private UserOrgBusinessService userOrgBusinessService;

    @Resource
    private UserUtil userUtil;

    @Resource
    private UserWechatGrpcService userWechatGrpcService;

    @Resource
    private RedisService redisService;

    @Resource(name = "userUserWechatWorkGrpcService")
    private UserWechatWorkGrpcService userWechatWorkGrpcService;

    @Resource
    private MailService mailService;

    @Resource
    private UserSmsService smsService;

    @Autowired
    private PhoneService phoneService;

    /*@Resource
    private OssService ossService;*/

    @Autowired
    private StorageService storageService;

    @Resource
    private UserMfaSettingService userMfaSettingService;

    @Resource
    private UserBusinessService userBusinessService;

    @Resource
    private UserJwtTokenUtil userJwtTokenUtil;

    @Resource
    private UserConvert userConvert;

    @Autowired
    private BaiduOcpcService baiduOcpcService;

    @Autowired
    private UserAccountDao userAccountDao;

    //@Autowired
    //private WeChatMessageSender weChatMessageSender;

    @Autowired
    private BusinessCacheUtil businessCacheUtil;

    @Value("${app.user.sensitive-word.enable:true}")
    private Boolean sensitiveWordEnable;

    @Override
    public ServiceResult<WxCodeSessionIdDTO> getAndSaveWxSessionInfoByCode(String code) {
        // 参数校验
        if (StringUtils.isBlank(code)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "code is not be null");
        }

        // 调用微信get_wx_code_to_session, 获取openid和session_key
        WxMiniUserInfoDTO wxMiniUserInfo = userWechatGrpcService.getWxMiniUserInfo(code);
        if (Objects.isNull(wxMiniUserInfo)) {
            return ServiceResult.fail(ResourceErrorCodeEnum.THIRD_PART, "调用微信get_wx_code_to_session失败");
        }

        UserDTO check = new UserDTO();
        check.setWxMiniOpenid(wxMiniUserInfo.getOpenid());
        ServiceResult<List<UserDTO>> userResult = userService.selectList(check);
        CacheWxMiniUserInfoDTO cacheDate = new CacheWxMiniUserInfoDTO();
        cacheDate.setChannel("微信");
        if (CollectionUtils.isNotEmpty(userResult.getData())) {
            UserDTO userDTO = userResult.getData().get(0);
            cacheDate.setUserName(userDTO.getName());
            cacheDate.setEmail(userDTO.getEmail());
            cacheDate.setMobile(userDTO.getPhone());
        }

        // 生成sessionId
        String sessionId = generateSessionId();
        cacheDate.setSessionId(sessionId);
        cacheDate.setOpenid(wxMiniUserInfo.getOpenid());
        cacheDate.setUnionid(wxMiniUserInfo.getUnionid());
        cacheDate.setSessionKey(wxMiniUserInfo.getSessionKey());
        Boolean result = userWechatGrpcService.cacheWxMiniUserInfo(cacheDate);

        if (BooleanStatusEnum.YES.getBoolValue().equals(result)) {
            WxCodeSessionIdDTO wxCodeSessionIdDTO = new WxCodeSessionIdDTO();
            wxCodeSessionIdDTO.setSessionId(sessionId);
            wxCodeSessionIdDTO.setOpenId(wxMiniUserInfo.getOpenid());
            return ServiceResult.success(wxCodeSessionIdDTO);
        }

        return ServiceResult.fail(ResourceErrorCodeEnum.THIRD_PART, "缓存微信小程序用户信息失败");
    }

    /**
     * 生成sessionId字符串
     *
     * @return java.lang.String
     * @author cuiqiongyu <qiongyu.cui@idiaoyan.cn>
     * @date 2022/03/30 18:41
     */
    private String generateSessionId() {
        return UUID.randomUUID().toString();
    }

    @Override
    public ServiceResult<List<WxSwitchDTO>> wxAccountSwitch(String userId) {
        // 参数校验
        if (StringUtils.isBlank(userId)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "userId not found");
        }
        // 获取用户信息
        ServiceResult<UserDTO> userResult = userService.selectById(userId);
        if (Objects.isNull(userResult.getData())) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "user not found");
        }
        UserDTO userDTO = userResult.getData();
        if (StringUtils.isBlank(userDTO.getPhone())) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "mobile lost");
        }
        List<UserDTO> userDTOList;
        // 邮箱或手机号查找用户并根据创建时间倒序
        if (StringUtils.isNotBlank(userDTO.getEmail())) {
            ServiceResult<List<UserDTO>> userListResult = userService.getUserByEmailOrPhone(UserStatusEnum.ACTIVATED.getStatus(), userDTO.getEmail(), userDTO.getPhone());
            userDTOList = userListResult.getData();
        } else {
            ServiceResult<List<UserDTO>> userListResult = userService.getUserByEmailOrPhone(UserStatusEnum.ACTIVATED.getStatus(), null, userDTO.getPhone());
            userDTOList = userListResult.getData();
        }
        List<WxSwitchDTO> orgDisplayList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(userDTOList)) {
            for (UserDTO user : userDTOList) {
                ServiceResult<OrganizationDTO> serviceResult = organizationService.selectByPrimaryKey(user.getOrgId());
                OrganizationDTO organizationDTO = serviceResult.getData();
                WxSwitchDTO wxSwitchDTO = new WxSwitchDTO();
                wxSwitchDTO.setUserId(userId);
                wxSwitchDTO.setOrgId(organizationDTO.getOrgId());
                wxSwitchDTO.setUserName(user.getUserName());
                wxSwitchDTO.setOrgName(organizationDTO.getName());
                wxSwitchDTO.setDisplayName(userBusinessService.getDisplayUserName(user));
                wxSwitchDTO.setOrgCode(organizationDTO.getCode());
                orgDisplayList.add(wxSwitchDTO);
            }
        }
        return ServiceResult.success(orgDisplayList);
    }

    private UserAndOrgListDTO getUserAndOrgList(String phone, String email) {
        List<UserDTO> userDTOList;
        // 邮箱或手机号查找用户并根据创建时间倒序
        if (StringUtils.isNotBlank(email)) {
            ServiceResult<List<UserDTO>> userListResult = userService.getUserByEmailOrPhone(UserStatusEnum.ACTIVATED.getStatus(), email, phone);
            userDTOList = userListResult.getData();
        } else {
            ServiceResult<List<UserDTO>> userListResult = userService.getUserByEmailOrPhone(UserStatusEnum.ACTIVATED.getStatus(), null, phone);
            userDTOList = userListResult.getData();
        }
        List<WxSwitchDTO> orgDisplayList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(userDTOList)) {
            for (UserDTO user : userDTOList) {
                ServiceResult<OrganizationDTO> serviceResult = organizationService.selectByPrimaryKey(user.getOrgId());
                OrganizationDTO organizationDTO = serviceResult.getData();
                WxSwitchDTO wxSwitchDTO = new WxSwitchDTO();
                wxSwitchDTO.setUserId(user.getUserId());
                wxSwitchDTO.setOrgId(organizationDTO.getOrgId());
                wxSwitchDTO.setUserName(user.getUserName());
                wxSwitchDTO.setOrgName(organizationDTO.getName());
                wxSwitchDTO.setDisplayName(userBusinessService.getDisplayUserName(user));
                wxSwitchDTO.setOrgCode(organizationDTO.getCode());
                orgDisplayList.add(wxSwitchDTO);
            }
        }
        UserAndOrgListDTO userAndOrgListDTO = new UserAndOrgListDTO();
        userAndOrgListDTO.setUserDTOList(userDTOList);
        userAndOrgListDTO.setOrgDisplayList(orgDisplayList);
        return userAndOrgListDTO;
    }


    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public ServiceResult<WxLoginDTO> wxMiniRegister(WxRegisterDTO wxRegisterDTO) {
        // 获取缓存数据wx_mp:{session_id}
        UserWxDataCacheDTO session = userWechatGrpcService.getWxCacheDataBySessionId(wxRegisterDTO.getSessionId(), UserOutterCacheKeyConstant.WX_MP);
        if (Objects.isNull(session)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, String.format("session %s not found", wxRegisterDTO.getSessionId()));
        }

        // 校验用户密码
        ServiceResult<String> result = PwdUtil.checkPassword(wxRegisterDTO.getPassword());
        if (!result.isSuccess()) {
            ServiceResult.fail(result.getErrorData(), result.getMsg());
        }

        // 校验注册手机号是否已经存在 获取测试注册白名单
        ServiceResult<String> checkPhoneRt = userAuthService.checkRegisterPhone(session.getPhone(), UserEditionEnum.FREE.getType());
        if (!checkPhoneRt.isSuccess()) {
            ServiceResult<UserLoginDTO> checkPhoneResult = ServiceResult.fail(checkPhoneRt.getMsg());
            checkPhoneResult.setErrorCode(checkPhoneRt.getErrorCode());
            return ServiceResult.fail(checkPhoneResult.getErrorData(), checkPhoneResult.getMsg());
        }

        // 获取行业以及对应区域的销售的邮箱
        IndustryDTO industryDTO = userAuthService.getIndustryAndSalesEmails(wxRegisterDTO.getRegisterIp(), wxRegisterDTO.getIndustryCode());
        if (industryDTO == null) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "industry_code is lost.");
        }

        // 生成公司code
        int orgSeq = sequenceService.incrementVersion(UserCacheKeyConstant.ORG_CODE_SEQ);
        String orgCode = String.format(CommonConstant.ORG_CODE_FORMAT, orgSeq);

        // 获取免费版套餐
        PackageDTO freePackage = packageGrpcService.getByType(PackageTypeEnum.FREE.getType());

        // 获取类型为基础试用版的套餐信息
        PackageDTO freeTrialPackage = packageGrpcService.getByType(PackageTypeEnum.FREE_TRIAL.getType());

        // 获取行业数据
        IndustryDTO industry = industryGrpcService.getByCode(wxRegisterDTO.getIndustryCode());

        // 行业与公司编码对应
        SampleOrgInfo sampleOrgInfo = sampleProperties.getByIndustryCode(industryDTO.getCode());
        String sampleOrgCode = sampleOrgInfo != null ? sampleOrgInfo.getOrgCode() : null;

        // 内部用户
        boolean checkUserIsInner = userUtil.checkUserIsInner(session.getPhone(), wxRegisterDTO.getEmail(), "");
        // 查询手机号归属地
        String location = phoneService.getPhoneLocation(session.getPhone());

        // 创建免费公司
        String orgId = DataBaseUtil.generateId();
        OrganizationDTO organizationDTO = new OrganizationDTO();
        organizationDTO.setOrgId(orgId);
        organizationDTO.setCode(orgCode);
        organizationDTO.setName(wxRegisterDTO.getOrgName());
        organizationDTO.setIndustryId(industry.getIndustryId());
        organizationDTO.setStatus(OrganizationStatusEnum.ACTIVATED.getStatus());
        organizationDTO.setAdminEmail(wxRegisterDTO.getEmail());
        organizationDTO.setAdminPhone(session.getPhone());
        organizationDTO.setAdminName(session.getPhone());
        organizationDTO.setCompleteFlag(OrgCompleteFlagEnum.COMPLETE.getType());
        organizationDTO.setInnerFlag(checkUserIsInner ? UserInnerFlagEnum.INNER.getType() : UserInnerFlagEnum.OUTTER.getType());
        organizationDTO.setSource(OrgSourceEnum.WECHAT_MINI_REGISTTER.getType());
        organizationDTO.setDistribution(industryDTO.getSalesEmails().get(0).split("@")[0]);
        organizationDTO.setLocation(location);
        organizationDTO.setSeoSource("小程序注册");
        organizationDTO.setSensitiveWordEnable(BooleanStatusEnum.toInteger(sensitiveWordEnable));
        organizationDTO.setCreateTime(new Date());
        organizationDTO.setUpdateTime(new Date());
        // 给公司设置套餐数据
        userOrgBusinessService.setOrgPackageInfo(organizationDTO, freeTrialPackage, freePackage, new Date());

        // 创建公司
        userOrgBusinessService.createFreeOrg(organizationDTO, sampleOrgCode);

        String userId = DataBaseUtil.generateId();
        UserDTO userDTO = new UserDTO();
        userDTO.setUserId(userId);
        userDTO.setOrgId(orgId);
        userDTO.setPhone(session.getPhone());
        userDTO.setWxUnionid(session.getUnionid());
        userDTO.setWxMiniOpenid(session.getOpenid());
        userDTO.setName(wxRegisterDTO.getName());
        userDTO.setUserName(session.getPhone());
        userDTO.setEmail(wxRegisterDTO.getEmail());
        userDTO.setPassword(wxRegisterDTO.getPassword());
        userDTO.setRegisterIp(wxRegisterDTO.getRegisterIp());
        userDTO.setInnerFlag(checkUserIsInner ? UserInnerFlagEnum.INNER.getType() : UserInnerFlagEnum.OUTTER.getType());
        // 创建免费系统用户
        userOrgBusinessService.createFreeSystemUser(userDTO);

        notifyFreeOrgCreated(orgCode, session.getPhone(), wxRegisterDTO.getOrgName(), wxRegisterDTO.getEmail(), new Date(), session.getPhone(), orgId);

        NotifyApplicationByEmailDTO emailDTO = new NotifyApplicationByEmailDTO();
        emailDTO.setToEmail(industry.getSalesEmails());
        emailDTO.setUsername(wxRegisterDTO.getName());
        emailDTO.setCompanyName(wxRegisterDTO.getOrgName());
        emailDTO.setCompanyType(industry.getName());
        emailDTO.setEmail(wxRegisterDTO.getEmail());
        emailDTO.setContent("无");
        emailDTO.setSubject(String.format("[%s申请信息-免费版]", settingProperties.getXmName()));
        emailDTO.setLoc(location);
        emailDTO.setSource("小程序注册");
        userUtil.notifyApplicationByEmail(emailDTO);

        // 设置AutoDTO build信息
        AuthDTO.AuthDTOBuilder builder = AuthDTO.builder();
        // 设置公司信息
        builder.orgId(organizationDTO.getOrgId());
        builder.orgCode(organizationDTO.getCode());
        builder.packageExpireTime(DateUtil.convertDteToString(organizationDTO.getPackageExpireTime(), DateUtil.YYYY_MM_DD));
        // 设置用户信息
        builder.userId(userDTO.getUserId());
        builder.realName(userDTO.getName());
        builder.avatar(userDTO.getAvatar());

        // 设置用户是否是系统管理员
        builder.superRole(1);

        // 生成jwt
        String token = userJwtTokenUtil.generateToken(builder.build());
        String refreshToken = userJwtTokenUtil.generateRefreshToken(organizationDTO.getCode(), userDTO.getUserId());

        if (StringUtils.isNotBlank(wxRegisterDTO.getTraceId())) {
            // 查询埋点数据
            ServiceResult<UserBookingTrackDTO> bookingTrackResult = trackService.selectById(wxRegisterDTO.getTraceId());
            UserBookingTrackDTO trackDTO = bookingTrackResult.getData();
            UserBookingTrackDTO userBookingTrackDTO = new UserBookingTrackDTO();
            userBookingTrackDTO.setOrgCode(orgCode);
            userBookingTrackDTO.setPlatform(UserBookingTrackPlatformEnum.WX_MINI_PROGRAM.getType());
            userBookingTrackDTO.setUtmSource(trackDTO.getUtmSource());
            userBookingTrackDTO.setPlan(trackDTO.getPlan());
            userBookingTrackDTO.setDevice(trackDTO.getDevice());
            userBookingTrackDTO.setName(wxRegisterDTO.getName());
            userBookingTrackDTO.setEmail(userDTO.getEmail());
            userBookingTrackDTO.setPhone(userDTO.getPhone());
            userBookingTrackDTO.setOrgName(wxRegisterDTO.getOrgName());
            userBookingTrackDTO.setIndustry(industry.getName());
            // 添加埋点
            trackService.insertSelective(userBookingTrackDTO);
        }
        GrowingioDTO growingioDTO = growingIoService.getUserProperty(userDTO, organizationDTO, freeTrialPackage.getName());
        WxLoginDTO wxLoginDTO = new WxLoginDTO();
        wxLoginDTO.setOrgCode(organizationDTO.getCode());
        wxLoginDTO.setToken(token);
        wxLoginDTO.setRefreshToken(refreshToken);
        wxLoginDTO.setGrowingio(growingioDTO);
        wxLoginDTO.setOrgId(orgId);

        // 开始copy sample
        userOrgBusinessService.copySample(organizationDTO, sampleOrgCode);
        return ServiceResult.success(wxLoginDTO);
    }


    @Override
    public ServiceResult<Object> wxOffiRegister(WxOffiRegisterDTO wxOffiRegisterDTO) {

        if (StringUtils.isNotBlank(wxOffiRegisterDTO.getPhone()) && StringUtils.isNotBlank(wxOffiRegisterDTO.getVcode())) {
            String key = UserCacheKeyConstant.BIND_MOBILE_PREFIX + wxOffiRegisterDTO.getPhone();
            Object cacheVcode = redisService.get(key);
            if (Objects.isNull(cacheVcode) || !wxOffiRegisterDTO.getVcode().equals(cacheVcode.toString())) {
                return ServiceResult.fail(ValidationErrorCodeEnum.VCODE_ERROR, "短信验证码错误");
            }
        }

        // 获取缓存数据User:wx_data{session_id}
        UserWxDataCacheDTO session = userWechatGrpcService.getWxCacheDataBySessionId(wxOffiRegisterDTO.getSessionId(), UserOutterCacheKeyConstant.USER_WX_DATA);
        if (Objects.isNull(session)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, String.format("session %s not found", wxOffiRegisterDTO.getSessionId()));
        }
        if (StringUtils.isBlank(session.getUnionid()) || StringUtils.isBlank(session.getOpenid())) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, String.format("session %s not found unionid or openid", wxOffiRegisterDTO.getSessionId()));
        }
        String wxNickName = StringUtils.isNotBlank(session.getNickname()) ? session.getNickname() : "";
        String headImgUrl = StringUtils.isNotBlank(session.getHeadImgUrl()) ? session.getHeadImgUrl() : "";

        if (StringUtils.isNotBlank(wxOffiRegisterDTO.getPhone())) {
            UserDTO check = new UserDTO();
            check.setPhone(wxOffiRegisterDTO.getPhone());
            check.setStatus(UserStatusEnum.ACTIVATED.getStatus());
            ServiceResult<List<UserDTO>> result = userService.listByCondition(check);
            List<UserDTO> userList = result.getData();

            // 检查是否可以直接把微信绑定给老用户
            if (userList.size() == 1) {
                UserDTO userDTO = userList.get(0);
                if (StringUtils.isBlank(userDTO.getWxUnionid())) {
                    userDTO.setWxUnionid(session.getUnionid());
                    userDTO.setWxOffiOpenid(session.getOpenid());
                    userDTO.setWxNickname(wxNickName);
                    userService.updateById(userDTO);

                    ServiceResult<WxLoginDTO> tokenResult = userAuthService.getTokenByUser(userDTO);
                    if (!tokenResult.isSuccess()) {
                        return ServiceResult.fail(tokenResult.getErrorData(), tokenResult.getMsg());
                    }
                    return ServiceResult.success(userConvert.wxLoginDTO2VO(tokenResult.getData()));
                }
            } else if (userList.size() > 1) {
                // 手机号对应多个用户时，选择
                List<OrgCodeDTO> orgCodeList = new ArrayList<>();
                for (UserDTO user : userList) {
                    ServiceResult<OrganizationDTO> organizationResult = organizationService.selectByPrimaryKey(user.getOrgId());
                    OrganizationDTO organizationDTO = organizationResult.getData();
                    if (Objects.isNull(organizationDTO)) {
                        return ServiceResult.fail(AuthErrorCodeEnum.USER_NAME_NOT_EXISTS, "user_name or password not true.");
                    }
                    OrgCodeDTO orgCodeDTO = new OrgCodeDTO();
                    orgCodeDTO.setOrgName(organizationDTO.getName());
                    orgCodeDTO.setOrgCode(organizationDTO.getCode());
                    orgCodeDTO.setOrgId(organizationDTO.getOrgId());
                    orgCodeList.add(orgCodeDTO);
                }
                UserWxDataDTO wxDataDTO = new UserWxDataDTO();
                wxDataDTO.setNickname(session.getNickname());
                wxDataDTO.setOpenid(session.getOpenid());
                wxDataDTO.setHeadImgUrl(session.getHeadImgUrl());
                wxDataDTO.setPhone(wxOffiRegisterDTO.getPhone());
                wxDataDTO.setUnionid(session.getUnionid());
                userWechatGrpcService.cacheUserWxData(wxOffiRegisterDTO.getSessionId(), wxDataDTO);

                WxMultiOrgDTO wxMultiOrgDTO = new WxMultiOrgDTO();
                wxMultiOrgDTO.setMultiOrg(true);
                wxMultiOrgDTO.setOrgCodeList(orgCodeList);
                wxMultiOrgDTO.setSessionId(wxOffiRegisterDTO.getSessionId());
                return ServiceResult.success(wxMultiOrgDTO);
            }
            // 不能绑定到老用户则创建新用户绑定手机号码
            UserRegisterDTO userRegisterDTO = new UserRegisterDTO();
            userRegisterDTO.setWxUnionid(session.getUnionid());
            userRegisterDTO.setWxOffiOpenid(session.getOpenid());
            userRegisterDTO.setWxNickname(wxNickName);
            userRegisterDTO.setHeadImgUrl(headImgUrl);
            userRegisterDTO.setPhone(wxOffiRegisterDTO.getPhone());
            String sessionId = businessCacheUtil.cacheWxUserInfo(userRegisterDTO);

            WxOffiResultDTO wxOffiResultDTO = new WxOffiResultDTO();
            wxOffiResultDTO.setIsRegister(1);
            wxOffiResultDTO.setNickname(wxNickName);
            wxOffiResultDTO.setSessionId(sessionId);
            return ServiceResult.success(wxOffiResultDTO);
        } else {
            // 微信公众号注册新用户
            WxLoginDTO wxLoginDTO = createWechatOffiAccountUser(session.getUnionid(), session.getOpenid(), wxNickName, headImgUrl, 1, null, wxOffiRegisterDTO.getRegisterIp());
            if (StringUtils.isNotBlank(wxOffiRegisterDTO.getTraceId())) {
                UserBookingTrackDTO check = new UserBookingTrackDTO();
                check.setBookingtrackId(wxOffiRegisterDTO.getTraceId());
                ServiceResult<List<UserBookingTrackDTO>> trackResult = trackService.selectBySelective(check);
                List<UserBookingTrackDTO> trackList = trackResult.getData();
                if (CollectionUtils.isNotEmpty(trackList)) {
                    UserBookingTrackDTO bt = trackList.get(0);
                    UserBookingTrackDTO trackDTO = new UserBookingTrackDTO();
                    trackDTO.setOrgCode(wxLoginDTO.getOrgCode());
                    trackDTO.setClickFlag(BooleanStatusEnum.YES.getStatus());
                    trackDTO.setUtmSource(bt.getUtmSource());
                    trackDTO.setPlan(bt.getPlan());
                    trackDTO.setDevice(bt.getDevice());
                    trackDTO.setPlatform(UserBookingTrackPlatformEnum.WX_OFFI_ACCOUNT.getType());
                    trackService.insertSelective(trackDTO);
                }
            }
            // 清理微信的信息
            userWechatGrpcService.deleteWxDataBySessionId(wxOffiRegisterDTO.getSessionId(), UserOutterCacheKeyConstant.USER_WX_DATA);
            // 异步回调百度回传转化数据
            baiduOcpcService.sendConvertData(wxOffiRegisterDTO.getNewType(), wxOffiRegisterDTO.getLogidUrl());
            return ServiceResult.success(wxLoginDTO);
        }
    }


    /**
     * 微信公众号注册新用户
     *
     * @param unionid
     * @param openid
     * @param nickname
     * @param headImgUrl
     * @param acceptFlag
     * @param phone
     * @param registerIp
     * @return com.bestcem.xm.user.service.dto.user.WxLoginDTO
     * @author Linzhijian <zhijian.lin@idiaoyan.com>
     * @date 2022/06/29 23:03
     */
    private WxLoginDTO createWechatOffiAccountUser(String unionid, String openid, String nickname, String headImgUrl, Integer acceptFlag, String phone, String registerIp) {
        String orgId = DataBaseUtil.generateId();
        String wxNickName = nickname;
        // 监测用户名重复问题
        if (StringUtils.isBlank(nickname)) {
            nickname = "倍市得用户" + getRandomUserNameStr(5);
        } else {
            UserDTO check = new UserDTO();
            check.setOrgId(orgId);
            check.setUserName(nickname);
            ServiceResult<List<UserDTO>> userResult = userService.listByCondition(check);
            if (CollectionUtils.isNotEmpty(userResult.getData())) {
                nickname = nickname + getRandomUserNameStr(5);
            }
        }
        // 是否是内部用户
        boolean checkUserIsInner = userUtil.checkUserIsInner("", "", nickname);

        // 生成公司code
        int orgSeq = sequenceService.incrementVersion(UserCacheKeyConstant.ORG_CODE_SEQ);
        String orgCode = String.format(CommonConstant.ORG_CODE_FORMAT, orgSeq);

        // 获取免费版套餐
        PackageDTO freePackage = packageGrpcService.getByType(PackageTypeEnum.FREE.getType());

        // 获取类型为基础试用版的套餐信息
        PackageDTO freeTrialPackage = packageGrpcService.getByType(PackageTypeEnum.FREE_TRIAL.getType());

        // 创建免费公司
        OrganizationDTO organizationDTO = new OrganizationDTO();
        organizationDTO.setOrgId(orgId);
        organizationDTO.setCode(orgCode);
        organizationDTO.setAdminPhone(phone);
        organizationDTO.setStatus(OrganizationStatusEnum.ACTIVATED.getStatus());
        organizationDTO.setAdminName(nickname);
        organizationDTO.setCompleteFlag(OrgCompleteFlagEnum.COMPLETE.getType());
        organizationDTO.setInnerFlag(checkUserIsInner ? UserInnerFlagEnum.INNER.getType() : UserInnerFlagEnum.OUTTER.getType());
        organizationDTO.setSource(OrgSourceEnum.WECHAT_OFFI_REGISTER.getType());
        organizationDTO.setSensitiveWordEnable(BooleanStatusEnum.toInteger(sensitiveWordEnable));

        // 给公司设置套餐数据
        userOrgBusinessService.setOrgPackageInfo(organizationDTO, freeTrialPackage, freePackage, new Date());

        // 创建公司
        try {
            userOrgBusinessService.createFreeOrg(organizationDTO, null);
        } catch (Exception e) {
            log.error(String.format("create_free_organization ERROR! org_id=%s", orgId));
        }

        String userId = DataBaseUtil.generateId();
        UserDTO userDTO = new UserDTO();
        userDTO.setUserId(userId);
        userDTO.setName("");
        userDTO.setOrgId(orgId);
        userDTO.setAvatar(headImgUrl);
        userDTO.setWxUnionid(unionid);
        userDTO.setWxOffiOpenid(openid);
        userDTO.setUserName(nickname);
        userDTO.setWxNickname(wxNickName);
        userDTO.setAcceptFlag(acceptFlag);
        userDTO.setPhone(phone);
        userDTO.setRegisterIp(registerIp);
        // 创建免费系统用户
        try {
            userOrgBusinessService.createFreeSystemUser(userDTO);
        } catch (Exception e) {
            log.error(String.format("create_free_system_user ERROR! org_id=%s", orgId));
        }

        // 设置AutoDTO build信息
        AuthDTO.AuthDTOBuilder builder = AuthDTO.builder();
        // 设置公司信息
        builder.orgId(organizationDTO.getOrgId());
        builder.orgCode(organizationDTO.getCode());
        builder.packageExpireTime(DateUtil.convertDteToString(organizationDTO.getPackageExpireTime(), DateUtil.YYYY_MM_DD));
        // 设置用户信息
        builder.userId(userDTO.getUserId());
        builder.realName(userDTO.getName());
        builder.avatar(userDTO.getAvatar());

        // 设置用户是否是系统管理员
        builder.superRole(1);

        // 生成jwt
        String token = userJwtTokenUtil.generateToken(builder.build());
        String refreshToken = userJwtTokenUtil.generateRefreshToken(organizationDTO.getCode(), userDTO.getUserId());
        // 获取埋点数据
        GrowingioDTO growingio = growingIoService.getUserProperty(userDTO, organizationDTO, freeTrialPackage.getName());
        WxLoginDTO wxLoginDTO = new WxLoginDTO();
        wxLoginDTO.setOrgCode(orgCode);
        wxLoginDTO.setOrgId(orgId);
        wxLoginDTO.setToken(token);
        wxLoginDTO.setRefreshToken(refreshToken);
        wxLoginDTO.setGrowingio(growingio);

        // 开始copy sample
        userOrgBusinessService.copySample(organizationDTO, null);
        return wxLoginDTO;
    }

    /**
     * 获取随机字符串不包含字符 用于生成账户名后缀
     *
     * @param size
     * @return java.lang.String
     * @author Linzhijian <zhijian.lin@idiaoyan.com>
     * @date 2022/06/28 22:36
     */
    private String getRandomUserNameStr(Integer size) {
        StringBuilder sb = new StringBuilder();
        String randomStr = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
        for (int i = 0; i < size; i++) {
            sb.append(randomStr.charAt(rand.nextInt(randomStr.length())));
        }
        return sb.toString();
    }


    @Override
    public ServiceResult<WxLoginDTO> wxLogin(String sessionId) {
        // 获取缓存数据User:wx_data
        UserWxDataCacheDTO wxDataDTO = userWechatGrpcService.getWxCacheDataBySessionId(sessionId, UserOutterCacheKeyConstant.USER_WX_DATA);

        UserDTO check = new UserDTO();
        check.setWxUnionid(wxDataDTO.getUnionid());
        check.setStatus(UserStatusEnum.ACTIVATED.getStatus());
        ServiceResult<List<UserDTO>> result = userService.getUserByCondition(check);
        if (!result.isSuccess() || CollectionUtils.isEmpty(result.getData())) {
            return ServiceResult.fail(ResourceErrorCodeEnum.WX_USER_NOT_FOUND, "wechat user not find");
        }

        UserDTO user = result.getData().get(0);
        OrganizationDTO organizationDTO = new OrganizationDTO();
        organizationDTO.setOrgId(user.getOrgId());
        organizationDTO.setStatus(OrganizationStatusEnum.ACTIVATED.getStatus());
        ServiceResult<List<OrganizationDTO>> organizationResult = organizationService.selectBySelective(organizationDTO);
        if (!organizationResult.isSuccess() || CollectionUtils.isEmpty(organizationResult.getData())) {
            return ServiceResult.fail(ResourceErrorCodeEnum.NOT_FOUND, String.format("Organization[id=%s] not found", user.getOrgId()));
        }
        OrganizationDTO organization = organizationResult.getData().get(0);
        ServiceResult<Void> lockResult = businessCacheUtil.checkUserLocked(organization.getCode(), user);
        if (!lockResult.isSuccess()) {
            // 用户被锁定
            return ServiceResult.fail(lockResult.getErrorData(), lockResult.getMsg());
        }
        // 判断是否需要mfa登录
        ServiceResult<JudgeNeedMfaLoginDTO> mfaResult = userMfaSettingService.judgeNeedMfaLogin(organization.getOrgId(), user);
//        if (!mfaResult.isSuccess()) {
//            return ServiceResult.fail(mfaResult.getErrorData(), mfaResult.getMsg());
//        }
        if (!mfaResult.isSuccess()) {
            return ServiceResult.fail(userConvert.needMfa2WxLoginDTO(mfaResult.getData()),
                    mfaResult.getMsg(), mfaResult.getErrorCode());
        }
        ServiceResult<WxLoginDTO> tokenResult = userAuthService.getTokenByUser(user);
        if (!result.isSuccess()) {
            return ServiceResult.fail(tokenResult.getErrorData(), tokenResult.getMsg());
        }
        return ServiceResult.success(tokenResult.getData());

    }

    @Override
    public ServiceResult<WxAuthViewDTO> wxAuthView(WxAuthViewRequestDTO requestDTO) {

        GetWxAuthViewDTO wxAuthView = userWechatGrpcService.getWxAuthView(requestDTO.getCode(), requestDTO.getEncryptedData(), requestDTO.getEncryptedData());
        UserDTO userDTO = new UserDTO();
        userDTO.setPhone(wxAuthView.getMobile());
        userDTO.setStatus(UserStatusEnum.ACTIVATED.getStatus());
        WxAuthViewDTO wxAuthViewDTO = new WxAuthViewDTO();
        List<WxUserViewDTO> wxUserViewDTOList = new ArrayList<>();
        // 数据库根据手机号码查找用户列表 create_time倒序
        List<UserDTO> userDTOList = userService.getUserListByCreateTimeSort(userDTO);
        for (UserDTO user : userDTOList) {
            OrganizationDTO organizationDTO = new OrganizationDTO();
            organizationDTO.setOrgId(user.getOrgId());
            organizationDTO.setStatus(OrganizationStatusEnum.ACTIVATED.getStatus());
            ServiceResult<List<OrganizationDTO>> orgListResult = organizationService.selectBySelective(organizationDTO);
            if (CollectionUtils.isNotEmpty(orgListResult.getData())) {
                OrganizationDTO org = orgListResult.getData().get(0);
                if (Objects.nonNull(org.getPackageExpireTime()) && new Date().after(org.getPackageExpireTime())) {
                    continue;
                }
                WxUserViewDTO wxUserViewDTO = new WxUserViewDTO();
                wxUserViewDTO.setUserId(user.getUserId());
                wxUserViewDTO.setUsername(user.getUserName());
                wxUserViewDTO.setOrgCode(org.getCode());
                wxUserViewDTO.setOrgId(org.getOrgId());
                wxUserViewDTO.setOrgName(org.getName());
                wxUserViewDTOList.add(wxUserViewDTO);
            }
        }
        wxAuthViewDTO.setSessionId(wxAuthView.getSessionId());
        wxAuthViewDTO.setUserViewList(wxUserViewDTOList);
        return ServiceResult.success(wxAuthViewDTO);
    }


    @Override
    public ServiceResult<WxTokenViewDTO> wxTokenView(WxTokenViewRequestDTO requestDTO) {

        // 获取缓存数据wx_mp:{session_id}
        UserWxDataCacheDTO tokenViewDTO = userWechatGrpcService.getWxCacheDataBySessionId(requestDTO.getSessionId(), UserOutterCacheKeyConstant.WX_MP);

        if (StringUtils.isBlank(tokenViewDTO.getPhone()) || StringUtils.isBlank(tokenViewDTO.getUnionid())) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "params lost");
        }
        OrganizationDTO organizationDTO = new OrganizationDTO();
        organizationDTO.setCode(requestDTO.getOrgCode());
        organizationDTO.setStatus(OrganizationStatusEnum.ACTIVATED.getStatus());
        ServiceResult<List<OrganizationDTO>> organizationDTOResult = organizationService.selectBySelective(organizationDTO);
        if (CollectionUtils.isEmpty(organizationDTOResult.getData())) {
            return ServiceResult.fail(AuthErrorCodeEnum.ORG_NOT_EXISTS, "organization code not exist.");
        }
        OrganizationDTO organization = organizationDTOResult.getData().get(0);
        if (organization.getPackageExpireTime().before(new Date())) {
            return ServiceResult.fail(AuthErrorCodeEnum.ORG_EXPIRE, DateUtil.convertDteToString(organization.getPackageExpireTime(), DateUtil.NORM_DATETIME_PATTERN));
        }
        ServiceResult<UserDTO> userDTOResult = userService.selectById(requestDTO.getUserId());
        if (!userDTOResult.isSuccess() || Objects.isNull(userDTOResult.getData())) {
            return ServiceResult.fail(AuthErrorCodeEnum.USER_NOT_EXISTS, "user not exist.");
        }
        UserDTO userDTO = userDTOResult.getData();
        userDTO.setWxUnionid(tokenViewDTO.getUnionid());
        userDTO.setWxMiniOpenid(tokenViewDTO.getOpenid());
        userService.updateById(userDTO);

        AuthDTO.AuthDTOBuilder builder = AuthDTO.builder();
        builder.orgId(organization.getOrgId());
        builder.orgCode(organization.getCode());
        builder.orgName(organization.getName());
        builder.userId(userDTO.getUserId());
        builder.realName(userDTO.getName());
        builder.avatar(userDTO.getAvatar());

        // 设置用户是否是系统管理员和高级管理员
        builder.superRole(userBusinessService.checkSuper(userDTO.getUserId(), userDTO.getOrgId()).getData());
        builder.senior(userBusinessService.checkSenior(userDTO.getUserId(), userDTO.getOrgId()).getData());

        // 生成jwt
        String token = userJwtTokenUtil.generateToken(builder.build());
        String refreshToken = userJwtTokenUtil.generateRefreshToken(requestDTO.getOrgCode(), userDTO.getUserId());

        PackageDTO packageDTO = packageGrpcService.getById(organization.getPackageId());
        GrowingioDTO growingioDTO = growingIoService.getUserProperty(userDTO, organization, packageDTO.getName());

        // 更新最后登录时间
        userAuthService.updateUserLastLoginTime(userDTO.getUserId());

        WxTokenViewDTO wxTokenViewDTO = new WxTokenViewDTO();
        wxTokenViewDTO.setToken(token);
        wxTokenViewDTO.setRefreshToken(refreshToken);
        wxTokenViewDTO.setGrowingio(growingioDTO);
        return ServiceResult.success(wxTokenViewDTO);

    }


    @Override
    public ServiceResult<WxLoginDTO> loginBySessionId(String sessionId) {

        // wx_mini_session
        UserWxDataCacheDTO wxMiniSession = userWechatGrpcService.getWxCacheDataBySessionId(sessionId, UserOutterCacheKeyConstant.WX_MINI_SESSION_PREFIX);
        if (Objects.isNull(wxMiniSession)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "session not found");
        }

        // 获取unionid
        if (StringUtils.isBlank(wxMiniSession.getUnionid())) {
            return ServiceResult.fail(ResourceErrorCodeEnum.NO_DATA, "unionId not found");
        }

        // 获取user
        UserDTO userDTO = new UserDTO();
        userDTO.setWxUnionid(wxMiniSession.getUnionid());
        userDTO.setStatus(UserStatusEnum.ACTIVATED.getStatus());
        ServiceResult<List<UserDTO>> userListResult = userService.selectList(userDTO);
        if (!userListResult.isSuccess() || CollectionUtils.isEmpty(userListResult.getData())) {
            return ServiceResult.fail(AuthErrorCodeEnum.USER_NOT_EXISTS, "user not found");
        }

        // 检查微信公众号是否存在，获取公司展示信息
        ServiceResult<WxLoginDTO> result = userAuthService.getTokenByUser(userListResult.getData().get(0));
        if (result.isSuccess()) {
            return result;
        }
        return ServiceResult.fail(result.getErrorData(), result.getMsg());
    }


    @Override
    public ServiceResult<String> wxOffiBind(String userId, String sessionId) {
        // 获取缓存数据User:wx_data:{session_id}
        UserWxDataCacheDTO userWxDataCacheDTO = userWechatGrpcService.getWxCacheDataBySessionId(sessionId, UserOutterCacheKeyConstant.USER_WX_DATA);
        if (Objects.isNull(userWxDataCacheDTO)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, String.format("session %s ont found", sessionId));
        }

        if (StringUtils.isBlank(userWxDataCacheDTO.getUnionid()) || StringUtils.isBlank(userWxDataCacheDTO.getOpenid())) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, String.format("session %s not found unionid or openid", sessionId));
        }

        // 判断用户是否已绑定
        UserDTO userDTO = new UserDTO();
        userDTO.setWxUnionid(userWxDataCacheDTO.getUnionid());
        ServiceResult<List<UserDTO>> userResult = userService.listByCondition(userDTO);

        // 微信用户已绑定，绑定失败
        if (!userResult.isSuccess() || CollectionUtils.isNotEmpty(userResult.getData())) {
            userWechatGrpcService.sendWxMessage(userWxDataCacheDTO.getOpenid(), "绑定失败，该微信已经绑定其他账号，如需登录此微信所在账号或解绑，你可以电脑打开bestcem.com选择微信登录。");
            return ServiceResult.fail(ResourceErrorCodeEnum.WX_USER_FOUND, "current wechat has bind user");
        }


        ServiceResult<UserDTO> serviceResult = userService.selectById(userId);
        if (!serviceResult.isSuccess() || Objects.isNull(serviceResult.getData())) {
            return ServiceResult.fail(ResourceErrorCodeEnum.STATUS_CHANGED, String.format("user id=%s is not exists", userId));
        }

        // 更新用户，绑定微信
        UserDTO wxUserDTO = new UserDTO();
        wxUserDTO.setUserId(userId);
        wxUserDTO.setWxUnionid(userWxDataCacheDTO.getUnionid());
        wxUserDTO.setWxOffiOpenid(userWxDataCacheDTO.getOpenid());
        wxUserDTO.setWxNickname(userWxDataCacheDTO.getNickname());
        ServiceResult<Integer> result = userService.updateById(wxUserDTO);
        if (!result.isSuccess() || result.getData() == 0) {
            return ServiceResult.fail(result.getErrorData(), result.getMsg());
        }
        return ServiceResult.success(userId);
    }

    @Override
    public ServiceResult<Object> wxAuthViewV2(WxAuthViewV2RequestDTO requestDTO) {

        // 获取缓存wx_mini_session
        UserWxDataCacheDTO wxMiniSession = userWechatGrpcService.getWxCacheDataBySessionId(requestDTO.getSessionId(), UserOutterCacheKeyConstant.WX_MINI_SESSION_PREFIX);
        if (StringUtils.isBlank(wxMiniSession.getSessionKey())) {
            return ServiceResult.fail(AppResourceErrorCode.NOT_FOUND, "wechat miniprom user info not found");
        }

        // 请求微信，获取sessionKey,缓存用户手机号码和unionid
        WxMiniUserMobileDTO userMobileDTO = userWechatGrpcService.getUserPhoneV2(wxMiniSession.getSessionKey(), requestDTO.getEncryptedData(), requestDTO.getIv());
        if (StringUtils.isBlank(userMobileDTO.getPhone())) {
            return ServiceResult.fail(ResourceErrorCodeConstants.THIRD_PART, "wechat User mobile is empty");
        }

        String sessionId = businessCacheUtil.genSessionId();
        userMobileDTO.setOpenid(wxMiniSession.getOpenid());
        userWechatGrpcService.cacheWxMiniUserData(sessionId, userMobileDTO);
        UserAndOrgListDTO userAndOrgList = getUserAndOrgList(userMobileDTO.getPhone(), null);
        if (CollectionUtils.isEmpty(userAndOrgList.getOrgDisplayList()) || settingProperties.getTestWhitePhoneList().contains(userMobileDTO.getPhone())) {
            FastCreateUserDTO userRegisterDTO = new FastCreateUserDTO();
            userRegisterDTO.setPhone(userMobileDTO.getPhone());
            userRegisterDTO.setWxMiniOpenid(userMobileDTO.getOpenid());
            businessCacheUtil.cacheFastCreateUser(sessionId, userRegisterDTO);

            WxV2RegisterDTO registerDTO = new WxV2RegisterDTO();
            registerDTO.setIsRegister(1);
            registerDTO.setSessionId(sessionId);
            registerDTO.setPhone(userMobileDTO.getPhone());
            return ServiceResult.success(registerDTO);
        } else if (userAndOrgList.getOrgDisplayList().size() == 1) {
            // 微信授权登录逻辑，如果匹配到只有一个用户，直接登录
            UserDTO userDTO = userAndOrgList.getUserDTOList().get(0);
            // 判断是否需要mfa登录
            ServiceResult<JudgeNeedMfaLoginDTO> mfaResult = userMfaSettingService.judgeNeedMfaLogin(userAndOrgList.getOrgDisplayList().get(0).getOrgId(), userDTO);
//            if (!mfaResult.isSuccess()) {
//                return ServiceResult.fail(mfaResult.getErrorData(), mfaResult.getMsg());
//            }
            if (!mfaResult.isSuccess()) {
                return ServiceResult.fail(userConvert.wxLoginDTO2VO(userConvert.needMfa2WxLoginDTO(mfaResult.getData())),
                        mfaResult.getMsg(), mfaResult.getErrorCode());
            }
            return ServiceResult.success(userConvert.wxLoginDTO2VO(userAuthService.getTokenByUser(userDTO).getData()));
        } else {
            // 多个企业
            UserLoginSessionDTO sessionDTO = new UserLoginSessionDTO();
            sessionDTO.setPhone(userMobileDTO.getPhone());
            sessionDTO.setWxMiniOpenid(userMobileDTO.getOpenid());
            businessCacheUtil.cacheFastLoginUser(sessionId, sessionDTO);
            WxV2OrgDTO wxV2OrgDTO = new WxV2OrgDTO();
            wxV2OrgDTO.setOrgDisplayList(userAndOrgList.getOrgDisplayList());
            wxV2OrgDTO.setMultiOrg(Boolean.TRUE);
            wxV2OrgDTO.setSessionId(sessionId);
            return ServiceResult.success(wxV2OrgDTO);
        }
    }


    @Override
    public ServiceResult<String> wxWorkCode(String code) {
        ServiceResult<String> result = userWechatWorkGrpcService.wxWorkCodeView(code);
        if (!result.isSuccess()) {
            return ServiceResult.fail(result.getErrorData(), result.getMsg());
        }
        return ServiceResult.success(result.getData());
    }

    @Override
    public void notifyFreeOrgCreated(String orgCode, String userName, String orgName, String email, Date expire, String phone, String orgId) {
        String expireStr = DateUtil.convertDteToString(expire, DateUtil.YYYY_MM_DD);
        Map<String, String> templateData = new HashMap<>();
        templateData.put("code", orgCode);
        templateData.put("userName", userName);
        templateData.put("companyName", orgName);
        templateData.put("expiryDT", expireStr);
        templateData.put("hotline", CommonConstant.BEST_HOTLINE);
        templateData.put("tmpl", EmailTemplateEnum.BOOK_NOTIFY_FREE_TEMPLATE.getFileName());
        templateData.put("org_id", StringUtils.isNotBlank(orgId) ? orgId : "");
        if (StringUtils.isNotBlank(email)) {
            notifyCompanyAcceptByEmail(email, templateData);
        }
        templateData.put("tmpl", SmsConstant.BOOK_NOTIFY_SMS_TMPL_FREE);
        if (StringUtils.isNotBlank(phone)) {
            notifyCompanyAcceptBySms(phone, templateData);
        }
    }

    public void notifyCompanyAcceptByEmail(String email, Map<String, String> dataMap) {
        String subject = settingProperties.getBestcemEmailSign() + "企业账号开通！";
        String tmpl = StringUtils.isNotBlank(dataMap.get("tmpl")) ? dataMap.get("tmpl") : EmailTemplateEnum.BOOK_NOTIFY_TEMPLATE.getFileName();
        HashMap<String, Object> data = new HashMap<>();
        data.put("code", dataMap.get("code"));
        data.put("userName", dataMap.get("userName"));
        data.put("companyName", dataMap.get("companyName"));
        data.put("corp_url", userUtil.getCorpUrl(dataMap.get("orgId"), dataMap.get("code"), "", "") + "/login");
        data.put("username", "superadmin");
        data.put("passwd", Objects.isNull(dataMap.get("passwd")) ? "123456" : dataMap.get("passwd"));
        data.put("hotline", Objects.isNull(dataMap.get("hotline")) ? CommonConstant.BEST_HOTLINE : dataMap.get("hotline"));
        data.put("expiry_date", dataMap.get("expiryDT"));
        data.put("today", DateUtil.convertDteToString(new Date(), DateUtil.YYYY_MM_DD));
        data.put("manager_mobile", dataMap.get("manager_mobile"));
        data.put("manager_email", dataMap.get("manager_email"));
        data.put("xm_name", CommonConstant.XM_NAME);
        //data.put("oss_url_prefix", ossService.getUrlPrefix());
        data.put("oss_url_prefix", storageService.getPropertiesValueBy(null, "domain") + storageService.getPropertiesValueBy(null, "base-path"));
        mailService.sendEmail(new String[]{email}, subject, tmpl, data);
    }

    public void notifyCompanyAcceptBySms(String phone, Map<String, String> map) {
        String tmpl = StringUtils.isNotBlank(map.get("tmpl")) ? map.get("tmpl") : SmsConstant.BOOK_NOTIFY_SMS_TMPL;
        // 短信提醒
        HashMap<String, Object> dataMap = new HashMap<>();
        dataMap.put("code", map.get("code"));
        dataMap.put("userName", map.get("userName"));
        dataMap.put("companyName", map.get("code"));
        dataMap.put("corp_url", userUtil.getCorpUrl(map.get("orgId"), map.get("code"), "", "") + "/login");
        dataMap.put("username", "superadmin");
        dataMap.put("password", StringUtils.isBlank(map.get("passwd")) ? "123456" : map.get("passwd"));
        dataMap.put("hotline", CommonConstant.BEST_HOTLINE);
        dataMap.put("expiry_date", map.get("expiryDT"));
        dataMap.put("manager_mobile", map.get("manager_mobile"));
        dataMap.put("manager_email", map.get("manager_email"));
        Integer status;
        String smsContent = "";
        try {
            smsContent = StringFormatUtil.format(tmpl, dataMap);
            status = NotifyStatusEnum.IS_SEND.getType();
        } catch (Exception e) {
            log.error("send notify_company_accept_by_sms error: %s", e);
            status = NotifyStatusEnum.SEND_FAILED.getType();
        }
        smsService.sendSms(phone, smsContent);
        RecordToOmDTO recordToOmDTO = new RecordToOmDTO();
        recordToOmDTO.setContent(smsContent);
        recordToOmDTO.setName("注册成功");
        recordToOmDTO.setOrgId(StringUtils.isNotBlank(map.get("org_id")) ? map.get("org_id") : "");
        recordToOmDTO.setReceiver(phone);
        recordToOmDTO.setType(NotifyTypeEnum.MOBILE.getType());
        recordToOmDTO.setSmsChannel(NotifySmsChannelEnum.YIMEI.getType());
        recordToOmDTO.setStatus(status);
        recordToOmDTO.setSendTime(DateUtil.convertDteToString(new Date(), DateUtil.NORM_DATETIME_PATTERN));
        recordToOmDTO.setTemplateId("");
        recordToOmDTO.setParams(JSON.toJSONString(map));
        userUtil.recordToOm(recordToOmDTO);
    }

    @Override
    public ServiceResult<WxLoginDTO> wxFastOrgLogin(WxFastOrgLoginDTO loginDTO) {

        // 获取缓存数据User:wx_data:{session_id}
        UserWxDataCacheDTO data = userWechatGrpcService.getWxCacheDataBySessionId(loginDTO.getSessionId(), UserOutterCacheKeyConstant.USER_WX_DATA);
        if (Objects.isNull(data)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, String.format("session %s not found", loginDTO.getSessionId()));
        }

        ServiceResult<OrganizationDTO> orgResult = organizationService.selectByCodeAndStatus(loginDTO.getOrgCode(), OrganizationStatusEnum.ACTIVATED.getStatus());
        if (!orgResult.isSuccess() && Objects.isNull(orgResult.getData())) {
            return ServiceResult.fail(AuthErrorCodeEnum.ORG_NOT_EXISTS, "org not find");
        }
        OrganizationDTO organizationDTO = orgResult.getData();
        UserDTO check = new UserDTO();
        check.setOrgId(organizationDTO.getOrgId());
        check.setPhone(data.getPhone());
        ServiceResult<List<UserDTO>> userResult = userService.getUserByCondition(check);
        if (!userResult.isSuccess() && CollectionUtils.isEmpty(userResult.getData())) {
            return ServiceResult.fail(AuthErrorCodeEnum.USER_NOT_EXISTS, "user not find");
        }
        UserDTO userDTO = userResult.getData().get(0);
        userDTO.setWxUnionid(data.getUnionid());
        userDTO.setWxOffiOpenid(data.getOpenid());
        userDTO.setWxNickname(data.getNickname());
        userService.updateById(userDTO);
        userWechatGrpcService.deleteWxDataBySessionId(loginDTO.getSessionId(), UserOutterCacheKeyConstant.USER_WX_DATA);
        ServiceResult<WxLoginDTO> tokenResult = userAuthService.getTokenByUser(userDTO);
        if (!tokenResult.isSuccess()) {
            return ServiceResult.fail(tokenResult.getErrorData(), tokenResult.getMsg());
        }
        return ServiceResult.success(tokenResult.getData());
    }


    @Override
    public ServiceResult<TicketSubscribeWxVO> ticketSubscribeWx(String openId, String userId, String orgId) {
        if (!ObjectId.isValid(userId)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "用户id错误");
        }
        UserDO exists = userAccountDao.selectByPrimaryKey(userId);
        if (Objects.isNull(exists)) {
            return ServiceResult.fail(ResourceErrorCodeEnum.STATUS_CHANGED, "当前登录用户无效");
        }
        UserWxDataCacheDTO wxUserInfo = userWechatGrpcService.getWxUserInfoByOpenId("openid:" + openId);
        if (Objects.isNull(wxUserInfo)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "微信用户信息获取失败");
        }
        if (ObjectUtils.isEmpty(wxUserInfo.getUnionid()) || Objects.isNull(wxUserInfo.getNickname())) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "微信用户信息获取异常");
        }
        // 倍市得用户绑定微信用户
        WxBindCodeEnum bindCode = WxBindCodeEnum.CREATE;
        // 注: 每个 WxUnionId 只会对应一个倍市得用户; 原python代码这里是查询list, 是因为它们的单体查询不能添加条件, 只能使用id获取
        User user = userAccountDao.getByWxUnionId(wxUserInfo.getUnionid());
        // 已绑定用户则进行解绑
        if (Objects.nonNull(user) && !ObjectUtils.isEmpty(user.getUserId())) {
            userAccountDao.unbindWechatByUserId(user.getUserId());
            // 已绑定用户与新绑定用户不是同一用户时, 发送解绑MQ
            //if (!user.getUserId().equals(userId)) {
            //    weChatMessageSender.weChatUnBind(user.getUserId(), orgId, openId);
            //}
            // 倍市得用户换绑微信用户
            bindCode = WxBindCodeEnum.UPDATE;
        }
        userAccountDao.bindWechat(userId, wxUserInfo.getUnionid(), openId, wxUserInfo.getNickname());
        return ServiceResult.success(new TicketSubscribeWxVO(userId, bindCode.getType()));
    }
}
